//
//  ServerEventsViewController.m
//  ws-mgmt-client
//
//  Created by Cliff Duffey on 9/14/09. Mage Labs.
//

#import "ServerEventsViewController.h"
#import "ConfigureServerViewController.h"
#import "RootViewController.h"
#import "ws_mgmt_clientAppDelegate.h"

@implementation ServerEventsViewController
@synthesize events, eventColor;
@synthesize serverListIndex;
@synthesize webData, enumerationContext, xmlParser, xmlEventsParser, enumerateSessionEstablished;
@synthesize logEventType, recordTypeResults, logEventMessage, recordMessageResults, logRecordNumber, recordRecordNumberResults;
@synthesize fault, faultMessage;
@synthesize serverURL, credentials, requestType;

#pragma mark SOAP/HTTP related methods


//Initiates either the Enumeration request or Pull request based on value of enumerationSessionEstablished
-(void)sendMessage
{
	NSString *soapMessage = [[NSString alloc] init];
	NSString *log = [[NSString alloc] init]; //log to query in the soap request
	NSString *event = [[NSString alloc] init]; //event to query in the soap request
	
	recordResults = FALSE;

	switch (requestType) {
		case appLog:
			log = [NSString stringWithFormat:@"Application"];
			event = [NSString stringWithFormat:@"1"];
			NSLog(@"Application Log");
			break;
		case securityLog:
			log = [NSString stringWithFormat:@"Security"];
			event = [NSString stringWithFormat:@"5"];
			NSLog(@"Security Log");
			break;
		default: //events log
			log = [NSString stringWithFormat:@"System"];
			event = [NSString stringWithFormat:@"1"];
			NSLog(@"Event Log");
			break;	
	}
	
	
	
	NSLog(@"%@\t%@", log, event);
	
	if(self.enumerateSessionEstablished == NO) //Create the appropriate SOAP message based on what request needs to be made (enumerate or pull)
	{
		
		soapMessage = [NSString stringWithFormat:
							 @"<?xml version=\"1.0\"?>\n"
							 "<s:Envelope xmlns:s=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/08/addressing\" xmlns:wsman=\"http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd\" xmlns:wsen=\"http://schemas.xmlsoap.org/ws/2004/09/enumeration\">\n"
							 "<s:Header>\n"
							 "<wsa:Action s:mustUnderstand=\"true\">http://schemas.xmlsoap.org/ws/2004/09/enumeration/Enumerate</wsa:Action>\n"
							 "<wsa:To s:mustUnderstand=\"true\">%@</wsa:To>\n"
							 "<wsman:ResourceURI s:mustUnderstand=\"true\">http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/Win32_NTLogEvent</wsman:ResourceURI>\n"
							 "<wsa:MessageID s:mustUnderstand=\"true\">uuid:8307f924-73d3-13d3-8002-338770290c00</wsa:MessageID>\n"
							 "<wsa:ReplyTo>\n"
							 "<wsa:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:Address>\n"
							 "</wsa:ReplyTo>\n"
							 "</s:Header>\n"
							 "<s:Body>\n"
							 "<wsen:Enumerate>\n"
							 "<wsman:Filter Dialect=\"http://schemas.dmtf.org/wbem/wsman/1/wsman/SelectorFilter\">\n"
							 "<wsman:SelectorSet>\n"
							 "<wsman:Selector Name=\"Logfile\">%@</wsman:Selector>\n"
							 "<wsman:Selector Name=\"EventType\">%@</wsman:Selector>\n"
							 "</wsman:SelectorSet>\n"
							 "</wsman:Filter>\n"
							 "</wsen:Enumerate>\n"
							 "</s:Body>\n"
							 "</s:Envelope>\n", self.serverURL, log, event
							 ];
	}
	else {
		soapMessage = [NSString stringWithFormat:
					   @"<?xml version=\"1.0\"?>\n"
					   "<s:Envelope xmlns:s=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/08/addressing\" xmlns:wsman=\"http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd\" xmlns:wsen=\"http://schemas.xmlsoap.org/ws/2004/09/enumeration\">\n"
					   "<s:Header>\n"
					   "<wsa:Action s:mustUnderstand=\"true\">\n"
					   "http://schemas.xmlsoap.org/ws/2004/09/enumeration/Pull"
					   "</wsa:Action>\n"
					   "<wsa:To s:mustUnderstand=\"true\">%@</wsa:To>\n"
					   "<wsman:ResourceURI s:mustUnderstand=\"true\">http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/Win32_NTLogEvent</wsman:ResourceURI>\n"
					   "<wsa:MessageID>\n"
					   "urn:uuid:b22747a9-ca15-41de-8c91-5a51bd88669c\n"
					   "</wsa:MessageID>\n"
					   "<wsa:ReplyTo>\n"
					   "<wsa:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:Address>\n"
					   "</wsa:ReplyTo>\n"
					   "</s:Header>\n"
					   "<s:Body>\n"
					   "<wsen:Pull>\n"
					   "<wsen:EnumerationContext>\n%@\n"
					   "</wsen:EnumerationContext>\n"
					   "<wsen:MaxTime>PT10S</wsen:MaxTime>\n"
					   "<wsen:MaxElements>100</wsen:MaxElements>\n"
					   "</wsen:Pull>\n"
					   "</s:Body>\n"
					   "</s:Envelope>", self.serverURL, enumerationContext
					   ];
					   		
	}
	
	/* create the HTTP request */
	NSURL *url = [NSURL URLWithString:self.serverURL]; 
	NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:url];
	NSString *msgLength = [NSString stringWithFormat:@"%d", [soapMessage length]];
	
	[theRequest addValue: @"application/soap+xml;charset=UTF-8" forHTTPHeaderField:@"Content-Type"];
	[theRequest addValue: @"Microsoft WinRM Client" forHTTPHeaderField:@"User-Agent"];
	[theRequest addValue: @"Keep-Alive" forHTTPHeaderField:@"Connection"];
	[theRequest addValue: self.credentials forHTTPHeaderField:@"Authorization"]; 
	[theRequest addValue: msgLength forHTTPHeaderField:@"Content-Length"];
	[theRequest setHTTPMethod:@"POST"];
	[theRequest setHTTPBody: [soapMessage dataUsingEncoding:NSUTF8StringEncoding]];
		
	/* establish the HTTP connection */
	NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
	
	if( theConnection ) //Make sure the connection 
	{
		webData = [[NSMutableData data] retain];

	}
	else
	{
		NSLog(@"theConnection is NULL");
	}
		
}

//Delegate functions for the HTTP request/response
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
	NSLog(@"connectionDidReceiveResponse");
	[webData setLength: 0];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
	NSLog(@"connectionDidReceiveData");
	[webData appendData:data];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
	NSLog(@"ERROR with theConnection, %@", [error localizedDescription]);
	
	[connection release];
	[webData release];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
	
	/*** 
	 Used for trouble-shooting -- comment out when not needed 
	 ***/	

	 NSString *theXML = [[NSString alloc] initWithBytes: [webData mutableBytes] length:[webData length] encoding:NSUTF8StringEncoding];
	 NSLog(@"%@",theXML);
	 [theXML release];
	
	//If we just made the enumeration request, we need to parse the response and make a pull request; 
	if(self.enumerateSessionEstablished == NO)  
	{
		self.enumerateSessionEstablished = YES;

		xmlParser = [[NSXMLParser alloc] initWithData: webData];
		[xmlParser setDelegate: self];
		[xmlParser setShouldResolveExternalEntities: YES];
		[xmlParser parse]; 
		
		[xmlParser release];
		
		[self sendMessage];
	} else 
	{		
		xmlEventsParser = [[NSXMLParser alloc] initWithData: webData];
		[xmlEventsParser setDelegate: self];
		[xmlEventsParser setShouldResolveExternalEntities: YES];
				
		[xmlEventsParser parse]; 
		
		[xmlEventsParser release];
		

		if( ([logRecordNumber intValue] > 1) && (fault == FALSE) )
		{
			NSLog(@"On record number %@", logRecordNumber);
			[self sendMessage];
		} 
		else	
		{
			if(fault)
				NSLog(@"Kicked out because we received a fault.");

			[connection release];
			[webData release];	
			[self.tableView reloadData]; //Refresh the table with the newly loaded data
			NSLog(@"Numer of events: %d", [events count]);
			NSLog(@"Last event added: %@", (NSString *)[events objectAtIndex: [events count] - 1]);		
		}
	}

}

#pragma mark XML parsing methods

-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *) namespaceURI qualifiedName:(NSString *)qName
   attributes: (NSDictionary *)attributeDict
{
	/* Depending on what element we are parsing, we need to set the appropriate flag and allocate space to store the parsed value
	 * We're interested in three elements:
	 * 1) The fault element in the response indicates something has gone wrong
	 * 2) The enumerationContext element in the enumeration response -- this is used to make the pull request
	 * 3) The Type element is from the pull response -- should contain a log event type (Warning, Information, Error)
	 * 4) The Message element is from the pull response -- provides a description of the log event
	 * 5) The RecordNumber element lets us know if there are more events to be pulled
	 */
	
	NSLog(@"parserDidStartElement");
	
	if( [elementName isEqualToString:@"s:Fault"]) 
	{
		NSLog(@"Fault detected");
		faultMessage = [[NSMutableString alloc] init];
		
		recordResults = FALSE;
		recordTypeResults = FALSE;
		recordMessageResults = FALSE;
		recordRecordNumberResults = FALSE;
		fault = TRUE;
		
	} else if( [elementName isEqualToString:@"n:EnumerationContext"]) 
	{
		if( enumerationContext )
			[enumerationContext release];
		
		enumerationContext = [[NSMutableString alloc] init];
		
		recordResults = TRUE;
		recordTypeResults = FALSE;
		recordMessageResults = FALSE;
		recordRecordNumberResults = FALSE;
		fault = FALSE;

	} else if( [elementName isEqualToString:@"p:Type"])
	{
		if( logEventType )
			[logEventType release];
		
		logEventType = [[NSMutableString alloc] init];
		
		recordResults = FALSE;
		recordTypeResults = TRUE;
		recordMessageResults = FALSE;
		recordRecordNumberResults = FALSE;
		fault = FALSE;

	} else if( [elementName isEqualToString:@"p:Message"])
	{
		if( logEventMessage )
			[logEventMessage release];
		
		logEventMessage = [[NSMutableString alloc] init];
		
		recordResults = FALSE;
		recordTypeResults = FALSE;
		recordMessageResults = TRUE;
		recordRecordNumberResults = FALSE;
		fault = FALSE;

	} else if( [elementName isEqualToString:@"p:RecordNumber"])
	{
		if( logRecordNumber )
			[logRecordNumber release];
		
		logRecordNumber = [[NSMutableString alloc] init];
		
		recordResults = FALSE;
		recordTypeResults = FALSE;
		recordMessageResults = FALSE;
		recordRecordNumberResults = TRUE;
		fault = FALSE;
		
	} 
}

// Append the value in the element as determined by the set flag
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
	NSLog(@"parserFoundCharacters");
	
	if(fault)
	{
	    // [faultMessage appendString:string];
	} else if(recordResults)
	{
		[enumerationContext appendString: string];
	} else if(recordMessageResults)
	{
		[logEventMessage appendString:string];
	} else if(recordTypeResults) 
	{
		[logEventType appendString:string];
	} else if(recordRecordNumberResults) 
	{
		[logRecordNumber appendString:string];
	}
}


//Set the flag to FALSE once we reach the closing element
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
	NSLog(@"parserDidEndElement");
	
	if( [elementName isEqualToString:@"n:EnumerationContext"])
	{
		recordResults = FALSE;
	} 
	else if( [elementName isEqualToString:@"p:Type"])
	{
		recordTypeResults = FALSE;
		
		if( logEventMessage && logEventType )
		{			
			
			if( !events )
				events = [[NSMutableArray alloc] initWithObjects: logEventMessage, nil];
			else 
				[events addObject: logEventMessage];
			
			if( !eventColor )
				eventColor = [[NSMutableArray alloc] initWithObjects: logEventType, nil];
			else 
				[eventColor addObject: logEventType];
			
//			NSLog(@"Added Color: %@\nFrom EventType: %@", (NSString *)[eventColor objectAtIndex: [eventColor count]-1], logEventType);
			
//			NSLog(@"Added Event: %@\nFrom EventMessage: %@", (NSString *)[events objectAtIndex: [events count]-1], logEventMessage);
			
		}
	} 
	else if( [elementName isEqualToString:@"p:Message"]) //Add the event message to the array acting as the data source for the table
	{
		recordMessageResults = FALSE;
	}
	else if( [elementName isEqualToString:@"p:RecordNumber"]) //Add the event message to the array acting as the data source for the table
	{
		recordRecordNumberResults = FALSE;
	}
}

#pragma mark View related functions

/*
 // The designated initializer.  Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
        // Custom initialization
    }
    return self;
}
*/


// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
	[super viewDidLoad];
	
	//Add a system 'Edit' button to the right
	UIBarButtonItem *saveButton = [[UIBarButtonItem alloc]
								   initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:self action:@selector(editButton:)];	
	self.navigationItem.rightBarButtonItem = saveButton;
	
	self.enumerateSessionEstablished = NO;
	self.recordMessageResults = NO;
	self.recordTypeResults = NO;
	self.fault = NO;
	
	[self sendMessage];
	
}

/*
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    // Return YES for supported orientations
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
*/

- (void)didReceiveMemoryWarning {
	// Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];
	
	// Release any cached data, images, etc that aren't in use.
}

- (void)viewDidUnload {
	// Release any retained subviews of the main view.
	// e.g. self.myOutlet = nil;
}


- (void)dealloc {
    [events release];
	[super dealloc];
}

#pragma mark Utility functions

- (IBAction) editButton: (id) sender 
{
	// Navigation logic to push the ConfigureServerViewContoller view controller.
	ConfigureServerViewController *configureServerViewController = [[ConfigureServerViewController alloc] initWithNibName:@"ConfigureServerViewController" bundle:nil];
	
	ws_mgmt_clientAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
	
	//Obtain the RootView Controller
	NSArray *viewControllers = [delegate.navigationController viewControllers];
	RootViewController *rootController = (RootViewController *)[viewControllers objectAtIndex:0];
	
	//Grab the current servers configuration items out of the array of dictionaries in the root view controller
	NSMutableDictionary *currentServerConfigItems = (NSMutableDictionary *)[rootController.serverList objectAtIndex:self.serverListIndex];
	
	//Pass those config items to the ConfigServerView controller
	configureServerViewController.url = [currentServerConfigItems objectForKey:@"URL"];
	configureServerViewController.name = [currentServerConfigItems objectForKey:@"Name"];
	configureServerViewController.username = [currentServerConfigItems objectForKey:@"Username"];
	configureServerViewController.password = [currentServerConfigItems objectForKey:@"Password"];
	configureServerViewController.isNewServer = NO;
	configureServerViewController.listIndex = serverListIndex;  

	[delegate.navigationController pushViewController:configureServerViewController animated:YES]; 
	
	[configureServerViewController release];
}

#pragma mark Table view methods

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}


// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return [self.events count];
}


// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    static NSString *CellIdentifier = @"ConfigServerCell";
    
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
    }
    
    // Set up the cell...
			
	cell.textLabel.font = [UIFont systemFontOfSize:10.0];
	
	cell.textLabel.lineBreakMode = UILineBreakModeWordWrap;
	cell.textLabel.numberOfLines = 0;
	
	cell.textLabel.text =  [self.events objectAtIndex: [indexPath row]]; 
    return cell;
}


- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
	
}


/*
 // Override to support conditional editing of the table view.
 - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
 // Return NO if you do not want the specified item to be editable.
 return YES;
 }
 */


/*
 // Override to support editing the table view.
 - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
 
 if (editingStyle == UITableViewCellEditingStyleDelete) {
 // Delete the row from the data source
 [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YES];
 }   
 else if (editingStyle == UITableViewCellEditingStyleInsert) {
 // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
 }   
 }
 */


/*
 // Override to support rearranging the table view.
 - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {
 }
 */


/*
 // Override to support conditional rearranging of the table view.
 - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
 // Return NO if you do not want the item to be re-orderable.
 return YES;
 }
 */



@end
